package com.yeskery.nut.aop.handler;

import com.yeskery.nut.annotation.aop.Before;
import com.yeskery.nut.annotation.aop.Compose;
import com.yeskery.nut.aop.Execution;
import com.yeskery.nut.bean.ApplicationContext;
import com.yeskery.nut.core.Order;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

/**
 * Before注解的方法处理器
 * @author sprout
 * @version 1.0
 * 2022-08-28 13:04
 */
public class BeforeProxyMethodHandler extends AspectProxyMethodHandler implements ComposeProxyMethodHandler {

    /**
     * 构建Before注解的方法处理器
     * @param applicationContext 应用上下文
     */
    public BeforeProxyMethodHandler(ApplicationContext applicationContext) {
        super(applicationContext);
    }

    @Override
    public boolean support(Method method) {
        return getProxyMethodAspectCacheMap().containsKey(method.toString()) || method.isAnnotationPresent(Before.class)
                || support(method, c -> c.beforeArray().length > 0);
    }

    @Override
    public void before(Method method, Execution execution, Object target) throws Exception {
        List<ProxyMethodTarget> proxyMethodTargetList = new ArrayList<>();
        Before beforeAnnotation = method.getAnnotation(Before.class);
        if (beforeAnnotation != null) {
            proxyMethodTargetList.add(new ProxyMethodTarget(beforeAnnotation.beanName(), beforeAnnotation.beanType(),
                    beforeAnnotation.method(), beforeAnnotation.order()));
        }
        Compose compose = getComposeAnnotation(method);
        if (compose != null) {
            for (Before before : compose.beforeArray()) {
                proxyMethodTargetList.add(new ProxyMethodTarget(before.beanName(), before.beanType(),
                        before.method(), before.order()));
            }
        }

        appendAspectProxyTarget(method, Before.class, proxyMethodTargetList);
        proxyMethodTargetList.sort(Comparator.comparing(Order::getOrder));
        for (ProxyMethodTarget proxyMethodTarget : proxyMethodTargetList) {
            doInjectMethod(target, proxyMethodTarget.getBeanName(), proxyMethodTarget.getBeanType(),
                    proxyMethodTarget.getMethodName(), new Object[]{execution});
        }
    }
}
